home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 6 / QRZ Ham Radio Callsign Database - Volume 6.iso / mac / files / amiga / csrc720j.lzh / amiga.c next >
C/C++ Source or Header  |  1993-08-23  |  35KB  |  1,260 lines

  1. /*
  2.  *  AMIGA.C - 19th Aug 1988 - System dependent functions.
  3.  *   Pete Hardie VE5VA
  4.  *
  5.  */
  6.  
  7. #include "mb.h"
  8. #include <intuition/intuition.h>
  9. #include <intuition/intuitionbase.h>
  10. #include <graphics/text.h>
  11. #include <devices/serial.h>
  12. #include <ctype.h>
  13. #include <time.h>
  14. #include "rexxhostbase.h"
  15.  
  16. extern struct RexxHost      *rexx_host;
  17. extern long rexxbit;
  18. extern struct Window *mywindow;
  19. extern struct IntuiMessage *NewMessage;
  20. short interflag = 0;
  21. short debug;
  22. long serfirst = 0L;
  23. char tmpstr[300];
  24. extern struct IOExtSer *Ser_Read;
  25. extern struct IOStdReq *Con_Read,*Con_Write;
  26. extern unsigned char rs_in[2];
  27. extern struct IOExtSer *Ser_Write;
  28. extern unsigned char rs_out[2];
  29. extern char optflags[];
  30. unsigned char gotstream = 0;
  31. extern char *tcmds[];
  32. /*
  33. {
  34.   "cono on\n",
  35.   "cono of\n",
  36.   "m on\n",
  37.   "m of\n"
  38. };
  39. */
  40. char passchr = 0,hfstream = 0,vhfstream = 0;
  41. char l_date[7], l_time[5];
  42. char z_date[7], z_time[5];
  43. char pt_flag = 0;
  44. extern short tapr_flag;
  45. short done_flag = 1;
  46. /*
  47.  *  Set the current I/O device.
  48.  */
  49.  
  50. ioport(pp)
  51. PORTS *pp;
  52. {
  53.   port = pp;
  54. }
  55.  
  56. /*
  57.  *  Return non-zero if a character waits at current input.
  58.  */
  59.  
  60. instat()
  61. {
  62.   register int st;
  63.  
  64.    if (port->dev is p_console) {
  65.       /* check for char at console */
  66.       if(CheckIO((struct IORequest *)Con_Read))return(1);
  67.       else return(0);
  68.    }
  69.    if(port->dev is p_tnc) {
  70.       /* check for char at serial port */
  71.       if(CheckIO((struct IORequest *)Ser_Read)) {
  72.          if(optflags[4])interflag = 1;
  73.          return(1);
  74.       }
  75.       else return(0);
  76.    }
  77.    return(0);
  78. }
  79. /* output char to serial port */
  80. outi(ch)
  81. char ch;
  82. {
  83.    schar(ch);
  84. }
  85.  
  86. /*
  87.  *  Put the character out the current port,
  88.  *  echo to console if the current port is not the console.
  89.  *  Note special handling of end-of-line character.
  90.  */
  91.  
  92. outchar(ch)
  93. char ch;
  94. {
  95.    if (ch is '\r') return;
  96.    if (ch is '\n') ch = '\r';
  97. /*
  98.  *  Put it out to the console, if it is going there.
  99.  */
  100.  
  101.    if ((port->dev is p_console) or port->ec)   {
  102.       if (ch is '\r') ttputc('\n');/* output '\n' */;
  103.       if(ch != passchr)ttputc(ch);
  104.    }
  105.  
  106. /*
  107.  *  If the port is the console, nothing more to do.
  108.  */
  109.  
  110.    if (port->dev is p_console) return;
  111.  
  112. /*
  113.  *  Stuff this byte out the port.
  114.  */
  115.  
  116.    outi(ch);
  117.    if (ch is '\r')
  118.       if (port->flags & p_lf) outi('\n');
  119. }
  120. unsigned char procstr[linelen];
  121. /* This routine must not use tmpstr to process the string because tmpstr
  122.    might be the input
  123. */
  124. outstr(cp)
  125. unsigned char *cp;
  126. {
  127.    register unsigned char *p,*q;
  128.    register int beepcount;
  129.    /* count the number of beeps in the line so that we can give an audible
  130.       as well as visual beep
  131.    */
  132.    if((port->dev is p_console) || port->ec) {
  133.       beepcount = 0;
  134.       for(q = cp,p = &procstr[0];*q && p < &procstr[linelen-1];q++) {
  135.          if(*q is '\r')continue;
  136.          *p++ = *q;
  137.          if(*q == '\007')beepcount++;
  138.       }
  139.       *p = 0;
  140.       Con_Write->io_Data = (APTR) &procstr[0];
  141.       Con_Write->io_Length = p-&procstr[0];
  142.       Con_Write->io_Command = CMD_WRITE;
  143.       DoIO((struct IORequest *)Con_Write);
  144.       while(beepcount--) {
  145.          beep();
  146.          Delay(15L);
  147.       }
  148.    }
  149.    /* now do the TNC if it is required.
  150.       The TNC appears to drop characters if I send the whole line
  151.       in one I/O so leave it at one character at a time. At 1200
  152.       baud this is not a problem.
  153.    */
  154.    if(port->dev is p_console)return;
  155.    for(q = cp,p = &procstr[0];*q && p < &procstr[linelen-1];q++) {
  156.       if(*q is '\r')continue;
  157.       if(*q is '\n') {
  158.          *p++ = '\r';
  159.          if (port->flags & p_lf)*p++ = '\n';
  160.       }
  161.       else *p++ = *q;
  162.    }
  163.    *p = 0;
  164.    Ser_Write->IOSer.io_Command = CMD_WRITE;
  165.    Ser_Write->IOSer.io_Length = p-&procstr[0];
  166.    Ser_Write->IOSer.io_Data = (APTR) &procstr[0];
  167.    DoIO((struct IORequest *)Ser_Write);
  168. }
  169.  
  170. short wait_timeout = 0;
  171. char cmdstring[100];
  172. FILE *fd;
  173. PORTS *devtnc;
  174. char *inittnc(infile,force)
  175. int force;
  176. char *infile;
  177. {
  178. /* This routine MUST NOT use tmpstr while the infile string is being used.
  179.    infile could be the tmpstr!
  180. */
  181.    register char *cp;
  182.    register char c;
  183.    register PORTS *p;
  184.    PORTS *oldport;
  185.    oldport = port;
  186.    wait_timeout = 0;
  187.    devtnc = 0;
  188.    /* Find the tnc port and set it as the current port */
  189.    for(p=porthd; p != NULL; p = p->next) {
  190.       if((devtnc == 0) && (p->id != 'Z'))devtnc = p;
  191.    }
  192.    if(devtnc == 0) {
  193.       printf("Can't find port\n");
  194.       donebeep();
  195.       endtimer();
  196.       cleanser();
  197.       freefcb();
  198.       closeterm();
  199.       clrbusy();
  200.       exit(1);
  201.    }
  202.    ioport(devtnc);
  203.    if((devtnc->dev == p_serial) || (devtnc->dev == p_nulmdm)) {
  204.       devtnc->ec = 1;
  205.       goto file_only;
  206.    }
  207.    if(!force)goto file_only;
  208.    /* Force a ^Q^C X  to the KAM or other TNC. If KAM is in mode other
  209.       than packet this will force it back.
  210.       If already in packet mode this will be interpreted as an XFLOW
  211.       request ... which won't hurt anything
  212.    */
  213.    outstr("\021\003X\n\n");
  214.    waitcmd(10);
  215.    /* have to turn off monitoring and conok so that nothing interferes
  216.       with the startup
  217.    */
  218.    alloff();
  219.    outstr("echo off\n"); /* echo MUST be off too */
  220.    waitcmd(10);
  221.    /* If wait_timeout is too big then the TNC probably isn't there
  222.       so let's get outta here
  223.    */
  224.    if(wait_timeout >= 3) {
  225.       fclose(port->fl);
  226.       donebeep();
  227.       endtimer();
  228.       cleanser();
  229.       freefcb();
  230.       closeterm();
  231.       clrbusy();
  232.       printf("Too many timeouts from TNC - possible reasons are:\n");
  233.       printf("1. TNC and AMIGA are not using same baudrate\n");
  234.       printf("2. The TNC is not plugged into the AMIGA\n");
  235.       printf("3. The TNC PARITY is not set to NONE (or SPACE)\n");
  236.       printf("4. There's too much monitored information buffered\n");
  237.       printf("   and it took too long to clear it - try again\n");
  238.       exit(1);
  239.    }
  240.    /* get the thing into sync with what comes in from the TNC which
  241.       may have stored up a lot of monitored stuff
  242.       Do this by sending out a command and watch for the reply.
  243.    */
  244.    outstr("txd\n");
  245.    do {
  246.       if((c = toupper(rdchar())) != 'T') {
  247.          ttputc(c);
  248.          continue;
  249.       }
  250.       ttputc('T');
  251.       if((c = toupper(rdchar())) != 'X') {
  252.          ttputc(c);
  253.          continue;
  254.       }
  255.       ttputc('X');
  256.       if((c = toupper(rdchar())) != 'D') {
  257.          ttputc(c);
  258.          continue;
  259.       }
  260.       ttputc('D');
  261.       break;
  262.    }while(1);
  263.    waitcmd(0);
  264.    if(!passchr) {
  265.       outstr("pass\n");
  266.       while((c = toupper(rdchar())) != 'P') {
  267.          ttputc(c);
  268.          /* If the reply contains '?' then there's no pass command */
  269.          if(c == '?') {
  270.             ttputs("NO PASS COMMAND\n\n");
  271.             goto file_only;
  272.          }
  273.       }
  274.       ttputc(c);
  275.       while((c = toupper(rdchar())) != '$')ttputc(c);
  276.       ttputc(c);
  277.       ttputc(c = rdchar());
  278.       passchr = hex(c) << 4;
  279.       ttputc(c = rdchar());
  280.       passchr |= hex(c);
  281.       waitcmd(0);
  282.    }
  283.    /* Now find out what the stream switching character(s) is(are) */
  284.    /* but forget it if there is no pass char */
  285.    if(passchr && !hfstream && !vhfstream) {    /* if not done before */
  286.       outstr("streamsw\n");
  287.       while((c = toupper(rdchar())) != 'W') {
  288.          ttputc(c);
  289.          if(c == '?') {
  290.             /* something's gone wrong. If there is a passchar then there
  291.                must also be a streamswitch. If not then clear passchr and
  292.                announce the problem
  293.             */
  294.             passchr = 0;
  295.             ttputs("Error from STREAMSW command - streamswitching off\n");
  296.             waitcmd(0);
  297.             goto file_only;
  298.          }
  299.       }
  300.       ttputc(c);
  301.       while((c = toupper(rdchar())) != '$')ttputc(c);
  302.       ttputc(c);
  303.       ttputc(c = rdchar());
  304.       vhfstream = hex(c) << 4;
  305.       ttputc(c = rdchar());
  306.       vhfstream |= hex(c);
  307.       /* IF it is a KAM there are two streamswitching chars to read */
  308.       if((c = rdchar()) == '/') {
  309.          ttputc(c);
  310.          hfstream = vhfstream;
  311.          ttputc(rdchar());         /* do the $ sign */
  312.          ttputc(c = rdchar());
  313.          vhfstream = hex(c) << 4;
  314.          ttputc(c = rdchar());
  315.          vhfstream |= hex(c);
  316.       }
  317.       else ttputc(c);
  318.       waitcmd(0);
  319.    }
  320.    sprintf(cmdstring,"\nPASS = $%02x, streamswitch VHF = ",passchr);
  321.    ttputs(cmdstring);
  322.    if((vhfstream > ' ') && (vhfstream < 0177))
  323.       sprintf(cmdstring,"%c",vhfstream);
  324.    else
  325.       sprintf(cmdstring,"$%02x",vhfstream);
  326.    ttputs(cmdstring);
  327.    if(hfstream) {
  328.       if((hfstream > ' ') && (hfstream < 0177))
  329.          sprintf(cmdstring," , HF = %c",hfstream);
  330.       else
  331.          sprintf(cmdstring," , HF = $%02x",hfstream);
  332.       ttputs(cmdstring);
  333.    }
  334.    ttputc('\n');
  335. file_only:
  336.    if((fd = fopen(infile,"r")) == NULL) {
  337.       sprintf(tmpstr,"Can't open %s\n",infile);
  338.       ioport(oldport);
  339.       return(tmpstr);
  340.    }
  341.    while(fgets(cmdstring,99,fd) != NULL) {
  342.       /* Ignore blank lines and comments */
  343.       if((cmdstring[0] == 0) || (cmdstring[0] == 012)
  344.                              || (cmdstring[0] == '#'))continue;
  345.       if(cmdstring[0] == '!') {
  346.          remnl(&cmdstring[0]);
  347.          do_system(&cmdstring[1]);
  348.          continue;
  349.       }
  350.       if(cmdstring[0] == '^') {
  351.          /* If it is ^S, send it and don't bother to read any more
  352.             of the file as the TNC won't respond anyway
  353.          */
  354.          if(toupper(cmdstring[1]) == 'S') {
  355.             outchar('\023');
  356.             break;
  357.          }
  358.          /* Ignore anything else. There's no point allowing ^Q because
  359.             the startup code at the beginning of inittnc must force ^Q
  360.             anyway, otherwise it wouldn't be able to get the tnc to
  361.             respond.
  362.          */
  363.          continue;
  364.       }
  365.       outstr(cmdstring);
  366.       waitcmd(0);
  367.  
  368.    }
  369.    fclose(fd);
  370.    ioport(oldport);
  371.    return((char *)0);
  372. }
  373. hex(c)
  374. char c;
  375. {
  376.    char k;
  377.    k = c;
  378.    if((c >= '0') && (c <= '9'))return(c - '0');
  379.    k = toupper(c);
  380.    if((k >= 'A') && (c <= 'F'))return(c - 'A' + 10);
  381.    return(-1);
  382. }
  383. flipdebug()
  384. {
  385.    debug ^= 1;
  386.    if(debug) {
  387.       ttputs("debug now ON\n");
  388.    }
  389.    else {
  390.       ttputs("debug now OFF\n");
  391.    }
  392. }
  393. extern unsigned char ichar;
  394. extern long keybit,windbit,readbit,timerbit;
  395. long getbits;
  396. struct timeRequest {
  397.    struct IORequest tr_node;
  398.    struct timeval tr_time;
  399. };
  400. extern struct timeRequest timermsg;
  401.  
  402. /* replace the original do_idle because it busy-waited ...
  403.    this version sleeps until there is something to do
  404. */
  405. extern short cursecs;
  406. do_idle()
  407. {
  408.    register unsigned char ch,*cp;
  409.    register PORTS *p;
  410.    int curmin,curmon;
  411.    ULONG class,error;
  412.    UWORD code;
  413.    struct RexxMsg *rexxmessage;  /* incoming rexx messages */
  414.    STRPTR Arg;       /* Temporary string pointer */
  415.    PORTS *saveport;
  416.    long waitbits;    /* waitbits MUST be local in CBBS because it is changed
  417.                         by various other routines as they see fit */
  418.  
  419.    cursor_off();
  420.    ioport(devtnc);
  421.    allon();
  422.    if((devtnc->dev == p_serial) || (devtnc->dev == p_nulmdm)) {
  423.       ttputs("\nIDLE\n");
  424.    }
  425.    cp = (unsigned char *) devtnc->line;
  426.    /* figure out time to next forward and set timer */
  427.    curtim();
  428.    curmin = 60 - cursecs;
  429.    settimer(curmin);
  430.    /* There might already be an unread char at the serial or console port */
  431.    serfirst = 0L;
  432.    clrbusy();
  433.    if(CheckIO((struct IORequest *)Ser_Read)) {
  434.       serfirst |= readbit;
  435.       Wait(readbit);
  436.    }
  437.    if(CheckIO((struct IORequest *)Con_Read)) {
  438.       serfirst |= keybit;
  439.       Wait(keybit);
  440.    }
  441.    waitbits = windbit | readbit | timerbit | keybit | rexxbit;
  442.    while(1)  {
  443.       /* If there was already a tnc char waiting then do it now */
  444.       if(serfirst) {
  445.          getbits = serfirst;
  446.          serfirst = 0L;
  447.       }
  448.       else {
  449.          getbits = Wait(waitbits);
  450.       }
  451.       if(windbit & getbits) {
  452.          while(NewMessage = (struct IntuiMessage *)GetMsg(mywindow->UserPort)) {
  453.             class = NewMessage->Class;
  454.             code = NewMessage->Code;
  455.             ReplyMsg((struct Message *)NewMessage);
  456.             if(class == IDCMP_CLOSEWINDOW) {
  457.                /* say a fond farewell, don't ask fer sure? */
  458.                if(done_flag) {
  459.                   if(timerbit & getbits) {
  460.                      WaitIO((struct IORequest *)&timermsg);
  461.                   }
  462.                   else {
  463.                      cantimer();
  464.                   }
  465.                   SetWindowTitles(mywindow,(UBYTE *)"",(UBYTE *)-1L);
  466.                   /* Need this to cancel out the clrbusy in done() */
  467.                   setbusy();
  468.                   done(1);
  469.                }
  470.             }
  471.          }
  472.       }
  473.       if(getbits & keybit) {
  474.          WaitIO((struct IORequest *)Con_Read);
  475.          ch = ichar;
  476.          Con_Read->io_Data = (APTR)&ichar;
  477.          Con_Read->io_Command = CMD_READ;
  478.          Con_Read->io_Length = 1;
  479.          SendIO((struct IORequest *)Con_Read);
  480.          if(ch == wchar) {
  481.             ioport(cport);
  482.             cursor_on();
  483.             /* could have a timerbit set here.
  484.                readbit could also be set but must handle that a
  485.                different way.
  486.             */
  487.             if(timerbit & getbits) {
  488.                WaitIO((struct IORequest *)&timermsg);
  489.             }
  490.             else {
  491.                cantimer();
  492.             }
  493.             return;
  494.          }
  495.          if(ch == '\033') {
  496.             ttputs("do_idle\n");
  497.          }
  498.       }
  499.       if(readbit & getbits) {
  500.          /* save a line and if it is a CONNECT then return */
  501.          if(error = WaitIO((struct IORequest *)Ser_Read)) {
  502.             printf("DO_IDLE error %ld\n",error);
  503.          }
  504.          ch = rs_in[0];
  505.          if(tapr_flag)ch &= 0177;
  506.          *cp = ch;   /* autolf is off so don't need to look for '\n' */
  507.          if((cp++ == (unsigned char *)devtnc->line + linelen -2)
  508.                   || (ch == '\r')) {
  509.             if(ch == '\r')cp--;
  510.             *cp++ = '\n';
  511.             *cp = 0;
  512.             /* Str_search cleans up the line and then does outstr */
  513.             ioport(cport);
  514.             str_search(devtnc->line);
  515.             ioport(devtnc);
  516.             p->flags setbit p_give;
  517.             if(iscon(devtnc->line)) {
  518.                /* readbit has been handled but timerbit could be set */
  519.                if(timerbit & getbits) {
  520.                   WaitIO((struct IORequest *)&timermsg);
  521.                }
  522.                else {
  523.                   cantimer();
  524.                }
  525.                BeginIO((struct IORequest *)Ser_Read);
  526.                return;
  527.             }
  528.             monitor();
  529.             cp = (unsigned char *)devtnc->line;
  530.          }
  531.          else if(ch == '\n')cp--;
  532.          BeginIO((struct IORequest *)Ser_Read);
  533.       }
  534.       /* REXX must turn off the clock because the forward may do it
  535.          anyway. Then once the forward is over, start the clock up
  536.          again.
  537.       */
  538.       if(rexxbit & getbits) {
  539.          while(rexxmessage = GetRexxMsg(rexx_host,0L)) {
  540.             /* If Arg is non-zero then this is an AREXX message from another
  541.                process.
  542.                If Arg is null then it is the result of a ReplyRexxCommand
  543.                from another process. This can't happen yet because we do not
  544.                send messages out.
  545.             */
  546.             if(Arg = GetRexxCommand(rexxmessage)) {
  547.                /* Must turn off the clock because the forward may do it
  548.                   anyway. Then once the forward is over, start the clock up
  549.                   again.
  550.                */
  551.                if(timerbit & getbits) {
  552.                   WaitIO((struct IORequest *)&timermsg);
  553.                }
  554.                else {
  555.                   cantimer();
  556.                }
  557.                getbits &= ~timerbit;
  558.                saveport = port;
  559.                /* Have to force it to use the console port for this */
  560.                ioport(cport);
  561.                port->opt1 = *Arg++;
  562.                port->opt2 = *Arg;
  563.                /* Have to reply to it early so that the sysop, or other
  564.                   process doesn't have to wait for the forward to finish.
  565.                   Send a non-zero secondary result to indicate OK.
  566.                */
  567.                ReplyRexxCommand(rexxmessage,0L,1L,0L);
  568.                alloff();
  569.                acmd();
  570.                allon();
  571.                ioport(saveport);
  572.                /* Turn clock back on again */
  573.                /* figure out time to next forward and set timer */
  574.                curtim();
  575.                curmin = 60 - cursecs;
  576.                settimer(curmin);
  577.             }
  578.             else {
  579.                FreeRexxCommand(rexxmessage);
  580.             }
  581.          }
  582.       }
  583.       /* This code is deliberately placed last. If a timer bit occurs
  584.          at the same time as a character arrives from the serial port
  585.          then this code will hang the serial port up because afwd()
  586.          tries to use the port again without clearing the existing char.
  587.          So workaround it. Putting the timer code here guarantees that
  588.          even if the ser char did occur it will be handled first and the
  589.          ser char code handles the problem of returning from this routine
  590.          with a timer bit set.
  591.       */
  592.       if(timerbit & getbits) {
  593.          WaitIO((struct IORequest *)&timermsg);
  594.          /* call the forwarding routine */
  595.          curtim();
  596.          curmin = 10 * (l_time[2] - '0') + (l_time[3] - '0');
  597.          afwd(curmin);
  598.          curmon = 10 * (l_date[2] - '0') + (l_date[3] - '0');
  599.  
  600.          if (s_param & s_log_on) if (curmon isnt log_mon) chglog();
  601.  
  602.          settimer(60);
  603.       }
  604.    }
  605. }
  606. /* IMPLEMENTATION BUG. In the original getdat it busy-idles and
  607.    if the port is transparent and DCD goes off while the port is
  608.    not idle, then it forces the mode to discon and then returns(true).
  609.    This code can only do this properly IF it can wait for DCD to go
  610.    off. I haven't even tried to implement this yet and not sure if it
  611.    can be done properly. I assume that there's a way to Wait() for a
  612.    DCD event but haven't checked it out
  613. */
  614. char *cp;
  615. /* MAXLEN is the longest unterminated line the justification routine
  616.    will accept before it rips out the word and keeps it for later use.
  617.    MAXJUST is the longest word that the routine will keep ... if the word
  618.    is any longer than this then it will just allow you to mess up the line!
  619. */
  620. #define MAXLEN 77
  621. #define MAXJUST 20
  622. unsigned char x_pos = 0; /* Position on line for right justification */
  623. unsigned char s_pos = 0; /* Position of last space on the line */
  624. char saveword[MAXJUST+2];
  625. getdat()
  626. {
  627.    register char *q;
  628.    register char ch;
  629.    register PORTS *p;
  630.    int eflag;
  631.    int curmin,serflg;
  632.    ULONG class,waitbits;
  633.    USHORT code;
  634.  
  635.  
  636.    p = port;
  637.    cp = p->line;
  638.    x_pos = s_pos = 0;
  639.    /* If there was a justified word left over from previous line .. put it
  640.       in here now.
  641.    */
  642.    if(*saveword) {
  643.       q = saveword;
  644.       while(*q) {
  645.          ttputc(*q);
  646.          *cp++ = *q++;
  647.          x_pos++;
  648.       }
  649.    }
  650.    *saveword = 0;
  651.    *cp = 0;
  652.    /* Is a timeout timer required? */
  653.    curmin = 0;
  654.    if(p->flags & p_dotmr) {
  655.       if((p->mode & idle) && (p->dev == p_tnc))
  656.          curmin = 2;
  657.       else
  658.          curmin = p->ctime;
  659.    }
  660.    /* The timer counts curmin down and each time it ticks the program
  661.       queries the serial driver to see if CD is still on if the user
  662.       is logged in on the modem. It doesn't bother for the sysop because
  663.       the modem won't be active.
  664.       I don't think that p_nulmdm needs to worry about this timer.
  665.    */
  666.    if(curmin) {
  667.       if(p->dev != p_serial) {
  668.          settimer(curmin);
  669.       }
  670.       else {
  671.          settimer(1);   /* set timeout timer if required to look for CD */
  672.       }
  673.    }
  674.    p->flags setbit p_dotmr;
  675.  
  676.    serfirst = 0L;
  677.    if(CheckIO((struct IORequest *)Ser_Read)) {
  678.       serfirst |= readbit;
  679.       Wait(readbit);
  680.    }
  681.    if(p == cport) {
  682.       waitbits = windbit | timerbit | keybit;
  683.    }
  684.    else {
  685.       if(CheckIO((struct IORequest *)Con_Read)) {
  686.          serfirst |= keybit;
  687.          Wait(keybit);
  688.       }
  689.       waitbits = windbit | readbit | timerbit | keybit;
  690.    }
  691.    while(1)  {
  692.       if(serfirst) {
  693.          getbits = serfirst;
  694.          serfirst = 0L;
  695.       }
  696.       else {
  697.          getbits = Wait(waitbits);
  698.       }
  699.       if(windbit & getbits) {
  700.          while(NewMessage = (struct IntuiMessage *)GetMsg(mywindow->UserPort)) {
  701.             class = NewMessage->Class;
  702.             code = NewMessage->Code;
  703.             ReplyMsg((struct Message *)NewMessage);
  704.             if(class == IDCMP_CLOSEWINDOW) {
  705.                /* say a fond farewell, don't ask fer sure? */
  706.                if(done_flag) {
  707.                   if(timerbit & getbits) {
  708.                      WaitIO((struct IORequest *)&timermsg);
  709.                   }
  710.                   else {
  711.                      cantimer();
  712.                   }
  713.                   SetWindowTitles(mywindow,(UBYTE *)"",(UBYTE *)-1L);
  714.                   done(1);
  715.                }
  716.             }
  717.          }
  718.       }
  719.       if(getbits & keybit) {
  720.          WaitIO((struct IORequest *)Con_Read);
  721.          ch = ichar;
  722.          Con_Read->io_Data = (APTR)&ichar;
  723.          Con_Read->io_Command = CMD_READ;
  724.          Con_Read->io_Length = 1;
  725.          SendIO((struct IORequest *)Con_Read);
  726.          if(ch == '\033') {
  727.             if(p == cport)ttputs("getdatCON\n");
  728.             else          ttputs("getdatTNC\n");
  729.          }
  730.          eflag = 0;
  731.          if(p != cport) {
  732.             if(ch == achar) {
  733.                p->mode = forced;
  734.                eflag = 1;
  735.             }
  736.             if(ch == tchar) {
  737.                p->flags setbit p_opreq;
  738.                eflag = 1;
  739.             }
  740.          }
  741.          else {
  742.             if(charf(ch)) {
  743.                eflag = 1;
  744.             }
  745.          }
  746.          /* If any of the previous three if statements want to
  747.             exit then check that the timer is off and then get out
  748.          */
  749.          if(eflag) {
  750.             if(timerbit & getbits) {
  751.                WaitIO((struct IORequest *)&timermsg);
  752.             }
  753.             else {
  754.                if(curmin)cantimer();
  755.             }
  756.             *cp = 0;
  757.             return(true);
  758.          }
  759.       }
  760.       if(readbit & getbits) {
  761.          WaitIO((struct IORequest *)Ser_Read);
  762.          ch = rs_in[0];
  763.          if(tapr_flag)ch &= 0177;
  764.          BeginIO((struct IORequest *)Ser_Read);
  765.          if(optflags[4])interflag = 1;
  766.          /* ignore stuff from the port if we are reading the console */
  767.          if((p != cport) && charf(ch)) {
  768.             if(timerbit & getbits) {
  769.                WaitIO((struct IORequest *)&timermsg);
  770.             }
  771.             else {
  772.                if(curmin)cantimer();
  773.             }
  774.             if(!(p->flags & p_trans)) {
  775.                if(isdis(p->line)) {
  776.                   if(!(p->mode & idle))p->mode = discon;
  777.                   return (true);
  778.                }
  779.                if(isretry(p->line)) {
  780.                   return (false);
  781.                }
  782.                if(isreq(p->line)) {
  783.                   p->flags setbit p_req;
  784.                   pcall(p->rcall,p->line+20);
  785.                   p->flags clrbit p_dotmr;
  786.                   return (false);
  787.                }
  788.             }
  789.             return (true);
  790.          }
  791.       }
  792.       if(timerbit & getbits) {
  793.          WaitIO((struct IORequest *)&timermsg);
  794.          if((curmin -= 1) <= 0) {
  795.             if(!(p->mode & idle))p->mode = timeout;
  796.             *cp = 0;
  797.             return (true);
  798.          }
  799.          /* Look for drop of carrier detect on the serial port */
  800.          if(p->dev == p_serial) {
  801.             if(getserstat() & 0x20) {
  802.                p->mode = discon;
  803.                *cp = 0;
  804.                return(true);
  805.             }
  806.          }
  807.          settimer(1);
  808.       }
  809.    }
  810. }
  811. charf(s)
  812. unsigned char s;
  813. {
  814.    register unsigned char ch;
  815.    PORTS *p;
  816.    register char *q,*r;
  817.    register int i;
  818.  
  819.  
  820.    p = port;
  821.    ch = s;
  822.    /* Ignore characters with high order bit set...they tie up the TNC */
  823.    if(ch > 0177)return(0);
  824.    *cp = ch;
  825.    if((cp >= p->line + linelen - 3) || (ch == '\r')) {
  826. do_lf:
  827.       if(ch == '\r')*cp = '\n';
  828.       *++cp = 0;
  829.       if(p->dev != p_console)ttputs(p->line);
  830.       if(p->flags & p_echo)ttputc('\n');
  831.       return(1);
  832.    }
  833.    if((ch >= ' ') && (ch <= 0176)) {
  834.       /*
  835.          Do justification for local user.
  836.       */
  837.       if(p->dev == p_console) {
  838.          if(ch == ' ') {
  839.             s_pos = x_pos;
  840.             /* If the space is at exactly the point we would have justified
  841.                the line then fake a CR anyway
  842.             */
  843.             if(x_pos == MAXLEN) {
  844.                ch = '\r';
  845.                *saveword = 0;
  846.                goto do_lf;
  847.             }
  848.          }
  849.          else {
  850.             /* It's not a space ... should we do the justify?
  851.             */
  852.             if(x_pos == MAXLEN) {
  853.                /* This word can't be longer than MAXJUST or we just leave
  854.                   it alone and let them mess up the line
  855.                */
  856.                if((i = (MAXLEN - s_pos)) < MAXJUST) {
  857.                   q = saveword;
  858.                   r = &p->line[s_pos+1];
  859.                   do {
  860.                      *q++ = *r++;
  861.                      ttputs("\b \b");
  862.                   }while(--i);
  863.                   *q = 0;
  864.                   cp = &p->line[s_pos];
  865.                   ch = '\r';
  866.                   goto do_lf;
  867.                }
  868.             }
  869.          }
  870.       }
  871.       x_pos++;
  872.       if (p->flags & p_echo) ttputc(ch);
  873.       cp++;
  874.       return(0);
  875.    }
  876.    switch(ch) {
  877.    default:
  878.       break;
  879.    case 26:    /* Control - Z */
  880.       cp++;
  881.       x_pos++;
  882.       break;
  883.    case '\t':
  884.       if(p->flags & p_echo) ttputc(ch);
  885.       s_pos = x_pos;
  886.       x_pos++;
  887.       cp++;
  888.       break;
  889.    case '\b':
  890.       if(cp > p->line) {
  891.          cp--;
  892.          if(p->flags & p_echo) ttputs("\b \b");
  893.          x_pos--;
  894.          /* If they wipe out a space we've got to find the previous one */
  895.          if(*cp == ' ') {
  896.             r = cp-1;
  897.             while(r > p->line) {
  898.                if(*r == ' ') break;
  899.                r--;
  900.             }
  901.             s_pos = r - p->line;
  902.          }
  903.  
  904.       }
  905.       break;
  906.  
  907.    case '\n':
  908.       if(cp is p->line) {
  909.          *cp = '\0';
  910.          return(1);
  911.       }
  912.       break;
  913.    }
  914.    return(0);
  915. }
  916.  
  917.  
  918. /* Remove the busy-wait in term() */
  919.  
  920. term(s)
  921. PORTS *s;
  922. {
  923.    register char ch,*cp;
  924.    register PORTS *m;
  925.    ULONG class,waitbits;
  926.    USHORT code;
  927.    byte ec;
  928.  
  929.    m = cport;
  930.    m->flags clrbit p_give;
  931.    ec = s->ec;
  932.    s->ec = true;
  933.    ioport(m);
  934.    serfirst = 0L;
  935.    if(CheckIO((struct IORequest *)Ser_Read)) {
  936.       serfirst |= readbit;
  937.       Wait(readbit);
  938.    }
  939.    waitbits = windbit | readbit | keybit;
  940.    while(1)  {
  941.       if(serfirst) {
  942.          getbits = serfirst;
  943.          serfirst = 0L;
  944.       }
  945.       else {
  946.          getbits = Wait(waitbits);
  947.       }
  948.       if(windbit & getbits) {
  949.          while(NewMessage = (struct IntuiMessage *)GetMsg(mywindow->UserPort)) {
  950.             class = NewMessage->Class;
  951.             code = NewMessage->Code;
  952.             ReplyMsg((struct Message *)NewMessage);
  953.             if(class == IDCMP_CLOSEWINDOW) {
  954.                /* say a fond farewell, don't ask fer sure? */
  955.                if(done_flag) {
  956.                   SetWindowTitles(mywindow,(UBYTE *)"",(UBYTE *)-1L);
  957.                   done(1);
  958.                }
  959.             }
  960.          }
  961.       }
  962.       if(getbits & keybit) {
  963.          WaitIO((struct IORequest *)Con_Read);
  964.          ch = ichar;
  965.          Con_Read->io_Data = (APTR)&ichar;
  966.          Con_Read->io_Command = CMD_READ;
  967.          Con_Read->io_Length = 1;
  968.          SendIO((struct IORequest *)Con_Read);
  969.          if(ch == rchar) {
  970.             m->flags setbit p_give;
  971.             s->ec = ec;
  972.             return;
  973.          }
  974.          if(ch == '\r')ch = '\n';
  975.          ttputc(ch);
  976.          if(ch == '\n') {
  977.             schar('\r');
  978.             if(s->flags & p_lf)schar('\n');
  979.          }
  980.          else schar(ch);
  981.          if(m->fl isnt NULL) if(ch isnt cpmeof)putc(ch,m->fl);
  982.       }
  983.       if(readbit & getbits) {
  984.          WaitIO((struct IORequest *)Ser_Read);
  985.          ch = rs_in[0];
  986.          if(tapr_flag)ch &= 0177;
  987.          BeginIO((struct IORequest *)Ser_Read);
  988. /*         if(streamswitch(ch))continue;   */
  989.          if(ch == '\r')ch = '\n';
  990.          if(m->fl isnt NULL) if(ch isnt cpmeof)putc(ch,m->fl);
  991.          ttputc(ch);
  992.       }
  993.    }
  994. }
  995.  
  996. /* This handles the stream characters.
  997.    BUT not any more ... KAM V3.0 has removed the streamdb command.
  998.    The first streamswitch character is always printed but is not passed
  999.    as data.
  1000.    The character immediately after the streamswitch is passed if it is the
  1001.    same streamswitch character, otherwise it is printed but also not passed
  1002.    as data.
  1003. streamswitch(ch)
  1004. unsigned char ch;
  1005. {
  1006.    if(gotstream) {
  1007.       if(ch == gotstream) {
  1008.          gotstream = 0;
  1009.       }
  1010.       else {
  1011.          gotstream = 0;
  1012.          ttputc(ch);
  1013.          return(1);
  1014.       }
  1015.    }
  1016.    else {
  1017.       if(ch && ((ch == vhfstream) || (ch == hfstream))) {
  1018.          gotstream = ch;
  1019.          ttputc(ch);
  1020.          return(1);
  1021.       }
  1022.    }
  1023.    return(0);
  1024. }
  1025. */
  1026.  
  1027.  
  1028. /* Replace the pause routine so that it can be used with TNC as well
  1029.    as the console. If routine times out after 2 minutes then it will
  1030.    return 'Q'.
  1031. */
  1032. pause()
  1033. {
  1034.  
  1035.    register char ch,*q;
  1036.    ULONG class,waitbits;
  1037.    USHORT code;
  1038.  
  1039.    if (port->user->state & u_pause) return ' ';
  1040.  
  1041.    q = &tmpstr[0];
  1042.    prtx(pausemsg);
  1043.    if(port->mode != local)outchar('\n');
  1044.    settimer(120);   /* set timeout timer  */
  1045.    waitbits = windbit | readbit | timerbit | keybit;
  1046.    serfirst = 0L;
  1047.    if(CheckIO((struct IORequest *)Ser_Read)) {
  1048.       serfirst |= readbit;
  1049.       Wait(readbit);
  1050.    }
  1051.    while(1)  {
  1052.       if(serfirst) {
  1053.          getbits = serfirst;
  1054.          serfirst = 0L;
  1055.       }
  1056.       else {
  1057.          getbits = Wait(waitbits);
  1058.       }
  1059.       if(windbit & getbits) {
  1060.          while(NewMessage = (struct IntuiMessage *)GetMsg(mywindow->UserPort)) {
  1061.             class = NewMessage->Class;
  1062.             code = NewMessage->Code;
  1063.             ReplyMsg((struct Message *)NewMessage);
  1064.             if(class == IDCMP_CLOSEWINDOW) {
  1065.                /* say a fond farewell, don't ask fer sure? */
  1066.                if(done_flag) {
  1067.                   if(timerbit & getbits) {
  1068.                      WaitIO((struct IORequest *)&timermsg);
  1069.                   }
  1070.                   else {
  1071.                      cantimer();
  1072.                   }
  1073.                   SetWindowTitles(mywindow,(UBYTE *)"",(UBYTE *)-1L);
  1074.                   done(1);
  1075.                }
  1076.             }
  1077.          }
  1078.       }
  1079.       if(getbits & keybit) {
  1080.          WaitIO((struct IORequest *)Con_Read);
  1081.          ch = toupper(ichar);
  1082.          Con_Read->io_Data = (APTR)&ichar;
  1083.          Con_Read->io_Command = CMD_READ;
  1084.          Con_Read->io_Length = 1;
  1085.          SendIO((struct IORequest *)Con_Read);
  1086.          if(timerbit & getbits) {
  1087.             WaitIO((struct IORequest *)&timermsg);
  1088.          }
  1089.          else {
  1090.             cantimer();
  1091.          }
  1092.          outchar('\n');
  1093.          return(ch);
  1094.       }
  1095.       if(readbit & getbits) {
  1096.          WaitIO((struct IORequest *)Ser_Read);
  1097.          ch = rs_in[0];
  1098.          if(tapr_flag)ch &= 0177;
  1099.          ch = toupper(ch);
  1100.          BeginIO((struct IORequest *)Ser_Read);
  1101.          *q++ = ch;
  1102.          if(ch == '\r') {
  1103.             if(timerbit & getbits) {
  1104.                WaitIO((struct IORequest *)&timermsg);
  1105.             }
  1106.             else {
  1107.                cantimer();
  1108.             }
  1109.             return(tmpstr[0]);
  1110.          }
  1111.       }
  1112.       /* check for timeout */
  1113.       if(timerbit & getbits) {
  1114.          WaitIO((struct IORequest *)&timermsg);
  1115.          return('Q');
  1116.       }
  1117.    }
  1118. }
  1119.  
  1120. /* Force modem to hangup */
  1121. force_modem()
  1122. {
  1123. /*   if(getserstat() & 0x20)return;*/
  1124.    Delay(150L);
  1125.    outstr("+++");
  1126.    waitcmd(5);
  1127.    Delay(10L);
  1128.    outstr("ATH0\n");
  1129.    waitcmd(5);
  1130. }
  1131. /* Skips leading blanks and then converts next two hex digits to binary.
  1132.    returns -1 on error.
  1133. */
  1134. fromhex(s)
  1135. char *s;
  1136. {
  1137.    register int i,j;
  1138.    register char *p;
  1139.    p = s;
  1140.    i = 0;
  1141.  
  1142.    while(*p == ' ')p++;
  1143.    if((i = hex(*p++)) < 0)return(-1);
  1144.    j = hex(*p);
  1145.    if(j < 0)return(-1);
  1146.    i <<= 4;
  1147.    i |= j;
  1148.    return(i);
  1149. }
  1150. /* replace waitcmd from mbtnc to reduce busy waits */
  1151. char *waitfor = "cmd:";
  1152. short wait_read;
  1153. waitcmd(x)
  1154. int x;
  1155. {
  1156.  
  1157.    register char ch;
  1158.    register int i;
  1159.    ULONG class,waitbits;
  1160.    USHORT code;
  1161.    wait_read = 0;
  1162.    if(port->dev == p_nulmdm)return;
  1163.    if(port->dev == p_serial) {
  1164.       waitfor = "ok\n\n";
  1165.    }
  1166.    else
  1167.       if(port->dev != p_tnc)return;
  1168.    if(s_flag & s_dv) i = 5;
  1169.    else i = 2;
  1170.    if(x) i = x;
  1171.    settimer(i);   /* set timeout timer  */
  1172.    i = 0;
  1173.    waitbits = windbit | readbit | timerbit | keybit;
  1174.    serfirst = 0L;
  1175.    if(CheckIO((struct IORequest *)Ser_Read)) {
  1176.       serfirst |= readbit;
  1177.       Wait(readbit);
  1178.    }
  1179.    while(1)  {
  1180.       if(serfirst) {
  1181.          getbits = serfirst;
  1182.          serfirst = 0L;
  1183.       }
  1184.       else {
  1185.          getbits = Wait(waitbits);
  1186.       }
  1187.       if(windbit & getbits) {
  1188.          while(NewMessage = (struct IntuiMessage *)GetMsg(mywindow->UserPort)) {
  1189.             class = NewMessage->Class;
  1190.             code = NewMessage->Code;
  1191.             ReplyMsg((struct Message *)NewMessage);
  1192.             if(class == IDCMP_CLOSEWINDOW) {
  1193.                /* say a fond farewell, don't ask fer sure? */
  1194.                if(done_flag) {
  1195.                   if(timerbit & getbits) {
  1196.                      WaitIO((struct IORequest *)&timermsg);
  1197.                   }
  1198.                   else {
  1199.                      cantimer();
  1200.                   }
  1201.                   SetWindowTitles(mywindow,(UBYTE *)"",(UBYTE *)-1L);
  1202.                   done(1);
  1203.                }
  1204.             }
  1205.          }
  1206.       }
  1207.       if(getbits & keybit) {
  1208.          WaitIO((struct IORequest *)Con_Read);
  1209.          ch = ichar;
  1210.          Con_Read->io_Data = (APTR)&ichar;
  1211.          Con_Read->io_Command = CMD_READ;
  1212.          Con_Read->io_Length = 1;
  1213.          SendIO((struct IORequest *)Con_Read);
  1214.          if(ch == '\033') { /* ESC key forces termination */
  1215.             ttputs("ESC\n");
  1216.             if(timerbit & getbits) {
  1217.                WaitIO((struct IORequest *)&timermsg);
  1218.             }
  1219.             else {
  1220.                cantimer();
  1221.             }
  1222.             return;
  1223.          }
  1224.       }
  1225.       if(readbit & getbits) {
  1226.          WaitIO((struct IORequest *)Ser_Read);
  1227.          wait_read = 1;
  1228.          ch = rs_in[0];
  1229.          if(tapr_flag)ch &= 0177;
  1230.          BeginIO((struct IORequest *)Ser_Read);
  1231. /*         if(streamswitch(ch))continue; */
  1232.          if(ch == '\r') {
  1233.             ch = '\n';
  1234.          }
  1235.          ttputc(ch);
  1236.          if(tolower(ch) == waitfor[i]) {
  1237.             i++;
  1238.             if(i == strlen(waitfor)) {
  1239.                if(timerbit & getbits) {
  1240.                   WaitIO((struct IORequest *)&timermsg);
  1241.                }
  1242.                else {
  1243.                   cantimer();
  1244.                }
  1245.                return;
  1246.             }
  1247.          }
  1248.          else {
  1249.             i = 0;
  1250.          }
  1251.       }
  1252.       /* check for timeout */
  1253.       if(timerbit & getbits) {
  1254.          WaitIO((struct IORequest *)&timermsg);
  1255.          wait_timeout++;
  1256.          return;
  1257.       }
  1258.    }
  1259. }
  1260.